package com.service;

import static com.def.GenericDef.EVT_BOX_HOLD;
import static com.def.GenericDef.EVT_BOX_HOLD_RELS;
import static com.def.GenericDef.EXIST_CARRIER;
import static com.def.GenericDef.E_READ_NOT_FOUND;
import static com.def.GenericDef.E_RET_BOX;
import static com.def.GenericDef.E_RET_PRD_ABN;
import static com.def.GenericDef.E_RET_PRD_INFO;
import static com.def.GenericDef.E_XPBOXHLD_BOX_IS_EMPT;
import static com.def.GenericDef.E_XPBOXHLD_INVALID_BOX_STATUS;
import static com.def.GenericDef.E_XPBOXHLD_INVALID_INPUT;
import static com.def.GenericDef.E_XPBOXHLD_INVALID_PRD_STATUS;
import static com.def.GenericDef.PROC_COMPLETE;
import static com.def.GenericDef.PROC_HOLD;
import static com.def.GenericDef.PROC_WAIT;
import static com.def.GenericDef.RETURN_CODE_OK;
import static com.def.GenericDef.RETURN_CODE_SET_ERROR;
import static com.def.GenericDef.RETURN_CODE_UNKNOWN;
import static com.def.GenericDef.RETURN_MESG_OK;
import static com.def.GenericDef.TRX_OUT;
import static com.def.GenericDef.T_XPBOXHLD;
import static com.def.GenericDef._NORMAL;
import static com.def.GenericDef._SPACE;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import com.dao.IRetBoxDao;
import com.dao.IRetPrdAbnDao;
import com.dao.IRetPrdInfoDao;
import com.icim.service.ICIMBaseService;
import com.model.Ret_box;
import com.model.Ret_prd_abn;
import com.model.Ret_prd_abnId;
import com.model.Ret_prd_info;
import com.rtnBean.NotFoundRtnBeen;
import com.tx.Xpboxhld.XpboxhldI;
import com.tx.Xpboxhld.XpboxhldO;
import com.tx.Xpboxhld.XpboxhldOA;
import com.util.GUIDGenerator;
import com.util.MqOpe;
import com.util.Util;

@Scope("prototype")
@Service("XpboxhldService")
public class XpboxhldService extends ICIMBaseService{
	private static Logger logger = Logger.getLogger(XpboxhldService.class);
	private static String TX_NAME = T_XPBOXHLD;

	private XpboxhldI inTrx;
	private XpboxhldO outTrx;
	private MqOpe mqOpe;

	private String gszMsgBuf = "";
	private Timestamp gEvtTimestamp;
	private Double gEvtTimeD;
	private String gEvtSeqID;

	@Autowired
	private IRetBoxDao retBoxDao;
	@Autowired
	private IRetPrdInfoDao retPrdInfoDao;
	@Autowired
	private IRetPrdAbnDao retPrdAbnDao;

	public String subMainProc(String strInMsg) {
		Session session = retPrdInfoDao.getCrSession();

		long rtnCode = _NORMAL;
		String outMsg = null;
		gszMsgBuf = "";
		gEvtTimestamp = Util.getCurrentTimestamp();
		gEvtTimeD = Util.getDoubleTime();
		gEvtSeqID = GUIDGenerator.javaGUID();

		inTrx = new XpboxhldI();
		outTrx = new XpboxhldO();
		outTrx.setTrx_id(TX_NAME);
		outTrx.setType_id(TRX_OUT);
		outTrx.setRtn_code(String.valueOf(RETURN_CODE_SET_ERROR));
		mqOpe = new MqOpe();

		try {
			inTrx = (XpboxhldI) mqOpe.inStr2Obj(strInMsg, inTrx);
			logger.info("InTrx is " + strInMsg);

			rtnCode = subMainProc2(inTrx.getAction_flg().toCharArray()[0]);
			if (rtnCode != _NORMAL) {
				TransactionAspectSupport.currentTransactionStatus()
						.setRollbackOnly();
				outTrx.setRtn_code(String.valueOf(rtnCode));
				outTrx.setRtn_mesg(gszMsgBuf);
			} else {
				outTrx.setRtn_code(String.valueOf(RETURN_CODE_OK));
				outTrx.setRtn_mesg(RETURN_MESG_OK);
				session.flush();
			}
		} catch (Exception ex) {
			TransactionAspectSupport.currentTransactionStatus()
					.setRollbackOnly();
			outTrx.setRtn_mesg(ex.toString());
			outTrx.setRtn_code(RETURN_CODE_UNKNOWN);
			logger.error(Util.stackTraceToString(ex));
		} finally {
			outMsg = mqOpe.obj2Str(outTrx);
		}
		return outMsg;
	}

	private long subMainProc2(char actionType) {
		long lRc = _NORMAL;
		switch (actionType) {
		case 'H': {
			lRc = boxHoldFunc(inTrx.getBox_id());
			break;
		}
		case 'R': {
			lRc = boxHoldReleaseFunc(inTrx.getBox_id());
			break;
		}
		case 'Q': {
			lRc = queryHoldSeqFunc(inTrx.getBox_id());
			break;
		}
		default: {
			gszMsgBuf = "Invalide type input: [" + actionType + "]";
			return E_XPBOXHLD_INVALID_INPUT;
		}
		}

		return lRc;
	}

	/**
	 * 查询Hold seq 明细
	 * 
	 * @param box_id
	 * @return
	 */
	private long queryHoldSeqFunc(String box_id) {
		// Get box info
		Ret_box ret_box = new Ret_box();
		List<Ret_box> ret_box_list = new ArrayList<Ret_box>();
		if ("".equals(box_id)){
			String sql = "FROM Ret_box WHERE BOX_STAT = 'HOLD'";
			ret_box_list = retBoxDao.queryRetBoxBySql(sql);
			
			List<XpboxhldO> outTx = new ArrayList<XpboxhldO>();
			for (int i=0;i<ret_box_list.size();i++){
				Ret_box box = ret_box_list.get(i);
				XpboxhldO ota = new XpboxhldO();
				ota = checkAllBoxHoldFunc(box);
				if (ota != null){
					outTx.add(ota);
//					outTrx = null;
				}
			}
			outTrx.setOary1(outTx);
			return _NORMAL;
		}else {
			ret_box = retBoxDao.get(box_id);
		}
		if (null == ret_box) {
			gszMsgBuf = new NotFoundRtnBeen(box_id, Ret_box.class).toString();
			return E_RET_BOX + E_READ_NOT_FOUND;
		}

		// Check box status
		if (!PROC_HOLD.equals(ret_box.getBox_stat())) {
			gszMsgBuf = "Box [" + box_id + "]'s status ["
					+ ret_box.getBox_stat() + "] is invalied, must["
					+ PROC_HOLD + "]!";
			return E_XPBOXHLD_INVALID_BOX_STATUS;
		}

		// Check box real empty
		if (!EXIST_CARRIER.equals(ret_box.getReal_emp())) {
			gszMsgBuf = "Box [" + box_id + "] is EMPT!";
			return E_XPBOXHLD_BOX_IS_EMPT;
		}

		// Get prd list
		List<Ret_prd_info> gRet_prd_infoList = new ArrayList<Ret_prd_info>();
		gRet_prd_infoList = retPrdInfoDao.getShtListInfo(box_id);
		if (null == gRet_prd_infoList) {
			gszMsgBuf = "No prd in box [" + box_id + "] !";
			return E_RET_PRD_INFO + E_READ_NOT_FOUND;
		}

		// Check prd status
		for (Ret_prd_info prd : gRet_prd_infoList) {
			if (!PROC_HOLD.equals(prd.getPrd_stat())) {
				gszMsgBuf = "Prd [" + prd.getPrd_seq_id() + "]'s status ["
						+ prd.getPrd_stat() + "] is invalied, must["
						+ PROC_HOLD + "]!";
				return E_XPBOXHLD_INVALID_PRD_STATUS;
			}
		}

		// Query hold seq
		List<Ret_prd_abn> ret_prd_abnList = new ArrayList<Ret_prd_abn>();
		ret_prd_abnList = retPrdAbnDao.getHoldDetailByPrd(gRet_prd_infoList
				.get(0).getPrd_seq_id());
		outTrx.setHold_seq_cnt(0);
		outTrx.setBox_id(box_id);
		outTrx.setBox_stat(ret_box.getBox_stat());
		outTrx.setNx_ope_id_fk(ret_box.getNx_ope_id_fk());
		outTrx.setNx_ope_ver_fk(ret_box.getNx_ope_ver_fk());
		
		if (!ret_prd_abnList.isEmpty()) {
			List<XpboxhldOA> oary = new ArrayList<XpboxhldOA>();
			for (Ret_prd_abn abn : ret_prd_abnList) {
				XpboxhldOA oa = new XpboxhldOA();
				oa.setBox_id(box_id);
				oa.setBox_stat(abn.getPrd_stat());
				oa.setPrd_seq_id_fk(abn.getId().getPrd_seq_id_fk());
				oa.setEvt_seq_id_fk(abn.getId().getEvt_seq_id_fk());
				oa.setEvt_usr(abn.getEvt_usr());
				oa.setEvt_timestamp(abn.getEvt_timestamp().toString());
				oary.add(oa);
			}
			outTrx.setOary(oary);
			outTrx.setHold_seq_cnt(oary.size());
		}

		return _NORMAL;
	}

	private XpboxhldO checkAllBoxHoldFunc(Ret_box ret_box){
		if (null == ret_box) {
			return null;
		}

		// Check box status
		if (!PROC_HOLD.equals(ret_box.getBox_stat())) {
			return null;
		}

		// Check box real empty
		if (!EXIST_CARRIER.equals(ret_box.getReal_emp())) {
			return null;
		}

		// Get prd list
		List<Ret_prd_info> gRet_prd_infoList = new ArrayList<Ret_prd_info>();
		gRet_prd_infoList = retPrdInfoDao.getShtListInfo(ret_box.getBox_id());
		if (null == gRet_prd_infoList) {
			return null;
		}

		// Check prd status
		for (Ret_prd_info prd : gRet_prd_infoList) {
			if (!PROC_HOLD.equals(prd.getPrd_stat())) {
				return null;
			}
		}

		// Query hold seq
		List<Ret_prd_abn> ret_prd_abnList = new ArrayList<Ret_prd_abn>();
		ret_prd_abnList = retPrdAbnDao.getHoldDetailByPrd(gRet_prd_infoList
				.get(0).getPrd_seq_id());
		
		XpboxhldO ota = new XpboxhldO();
		ota.setHold_seq_cnt(0);
		ota.setBox_id(ret_box.getBox_id());
		ota.setBox_stat(ret_box.getBox_stat());
		
		ota.setNx_ope_id_fk(ret_box.getNx_ope_id_fk());
		ota.setNx_ope_ver_fk(ret_box.getNx_ope_ver_fk());
		
		if (!ret_prd_abnList.isEmpty()) {
			List<XpboxhldOA> oary = new ArrayList<XpboxhldOA>();
			for (Ret_prd_abn abn : ret_prd_abnList) {
				XpboxhldOA oa = new XpboxhldOA();
				oa.setBox_id(ret_box.getBox_id());
				oa.setBox_stat(abn.getPrd_stat());
				oa.setPrd_seq_id_fk(abn.getId().getPrd_seq_id_fk());
				oa.setEvt_seq_id_fk(abn.getId().getEvt_seq_id_fk());
				oa.setEvt_usr(abn.getEvt_usr());
				oa.setEvt_timestamp(abn.getEvt_timestamp().toString());
				oary.add(oa);
			}
			ota.setOary(oary);
			ota.setHold_seq_cnt(oary.size());
		}

		return ota;
	}
	
	/**
	 * 按箱子取消HOLD
	 * 
	 * @param box_id
	 * @return
	 */
	private long boxHoldReleaseFunc(String box_id) {
		long lRc = _NORMAL;

		// Get box info
		Ret_box ret_box = new Ret_box();
		ret_box = retBoxDao.get(box_id);
		if (null == ret_box) {
			gszMsgBuf = new NotFoundRtnBeen(box_id, Ret_box.class).toString();
			return E_RET_BOX + E_READ_NOT_FOUND;
		}

		// Check box status
		if (!PROC_HOLD.equals(ret_box.getBox_stat())) {
			gszMsgBuf = "Box [" + box_id + "]'s status ["
					+ ret_box.getBox_stat() + "] is invalied, must ["
					+ PROC_HOLD + "]!";
			return E_XPBOXHLD_INVALID_BOX_STATUS;
		}

		// Check box real empty
		if (!EXIST_CARRIER.equals(ret_box.getReal_emp())) {
			gszMsgBuf = "Box [" + box_id + "] is EMPT!";
			return E_XPBOXHLD_BOX_IS_EMPT;
		}

		// Get prd list
		List<Ret_prd_info> gRet_prd_infoList = new ArrayList<Ret_prd_info>();
		gRet_prd_infoList = retPrdInfoDao.getShtListInfo(box_id);
		if (null == gRet_prd_infoList) {
			gszMsgBuf = "No prd in box [" + box_id + "] !";
			return E_RET_PRD_INFO + E_READ_NOT_FOUND;
		}

		// Check prd status
		for (Ret_prd_info prd : gRet_prd_infoList) {
			if (!PROC_HOLD.equals(prd.getPrd_stat())) {
				gszMsgBuf = "Prd [" + prd.getPrd_seq_id() + "]'s status ["
						+ prd.getPrd_stat() + "] is invalied, must ["
						+ PROC_HOLD + "]!";
				return E_XPBOXHLD_INVALID_PRD_STATUS;
			}

			// Get hold record
			Ret_prd_abn ret_prd_abn = new Ret_prd_abn();
			Ret_prd_abnId ret_prd_abnId = new Ret_prd_abnId();
			ret_prd_abnId.setPrd_seq_id_fk(prd.getPrd_seq_id());
			ret_prd_abnId.setEvt_seq_id_fk(inTrx.getHld_evt_seq());
			ret_prd_abn = retPrdAbnDao.get(ret_prd_abnId);
			if (null == ret_prd_abn) {
				gszMsgBuf = new NotFoundRtnBeen(ret_prd_abnId.toString(),
						Ret_prd_abn.class).toString();
				return E_RET_PRD_ABN + E_READ_NOT_FOUND;
			}
			retPrdAbnDao.delete(ret_prd_abn);

			// 是否仍有hold
			String sqlGetHldRecord = "FROM Ret_prd_abn WHERE id.prd_seq_id_fk='"
					+ prd.getPrd_seq_id() + "'";
			List<Ret_prd_abn> ret_prd_abnList = new ArrayList<Ret_prd_abn>();
			ret_prd_abnList = retPrdAbnDao.find(sqlGetHldRecord);
			if (ret_prd_abnList.isEmpty()) {
				prd.setPrd_stat(ret_prd_abn.getPv_prd_stat());
				prd.setPv_prd_stat_fk(_SPACE);
			}

			// Update prd info
			prd.setEvt_seq_id(gEvtSeqID);
			prd.setEvt_timestamp(gEvtTimestamp);
			prd.setEvt_time_d(gEvtTimeD);
			prd.setEvt_usr(inTrx.getEvt_usr());
			prd.setEvt_cate(EVT_BOX_HOLD_RELS);
			prd.setSht_ope_msg(inTrx.getHld_note());

			retPrdInfoDao.update(prd);
		}

		ret_box.setBox_stat(gRet_prd_infoList.get(0).getPrd_stat());
		retBoxDao.update(ret_box);

		return lRc;
	}

	/**
	 * 按箱子HOLD
	 * 
	 * @param box_id
	 * @return
	 */
	private long boxHoldFunc(String box_id) {
		long lRc = _NORMAL;

		// Get box info
		Ret_box ret_box = new Ret_box();
		ret_box = retBoxDao.get(box_id);
		if (null == ret_box) {
			gszMsgBuf = new NotFoundRtnBeen(box_id, Ret_box.class).toString();
			return E_RET_BOX + E_READ_NOT_FOUND;
		}

		// Check box status
		if (PROC_WAIT.equals(ret_box.getBox_stat())
				|| PROC_HOLD.equals(ret_box.getBox_stat())
				|| PROC_COMPLETE.equals(ret_box.getBox_stat())) {
			;
		} else {
			gszMsgBuf = "Box [" + box_id + "]'s status ["
					+ ret_box.getBox_stat() + "] is invalied!";
			return E_XPBOXHLD_INVALID_BOX_STATUS;
		}

		// Check box real empty
		if (!EXIST_CARRIER.equals(ret_box.getReal_emp())) {
			gszMsgBuf = "Box [" + box_id + "] is EMPT!";
			return E_XPBOXHLD_BOX_IS_EMPT;
		}

		// Get prd list
		List<Ret_prd_info> gRet_prd_infoList = new ArrayList<Ret_prd_info>();
		gRet_prd_infoList = retPrdInfoDao.getShtListInfo(box_id);
		if (null == gRet_prd_infoList) {
			gszMsgBuf = "No prd in box [" + box_id + "] !";
			return E_RET_PRD_INFO + E_READ_NOT_FOUND;
		}

		// Check prd status
		for (Ret_prd_info prd : gRet_prd_infoList) {
			if (PROC_WAIT.equals(prd.getPrd_stat())
					|| PROC_HOLD.equals(prd.getPrd_stat())
					|| PROC_COMPLETE.equals(prd.getPrd_stat())) {
				;
			} else {
				gszMsgBuf = "Prd [" + prd.getPrd_seq_id() + "]'s status ["
						+ prd.getPrd_stat() + "] is invalied!";
				return E_XPBOXHLD_INVALID_PRD_STATUS;
			}
		}

		// Real Hold proc
		for (Ret_prd_info prd : gRet_prd_infoList) {
			if (!PROC_HOLD.equals(prd.getPrd_stat())) {
				prd.setPv_prd_stat_fk(prd.getPrd_stat());
				prd.setPrd_stat(PROC_HOLD);
			}
			prd.setEvt_seq_id(gEvtSeqID);
			prd.setEvt_timestamp(gEvtTimestamp);
			prd.setEvt_time_d(gEvtTimeD);
			prd.setEvt_usr(inTrx.getEvt_usr());
			prd.setEvt_cate(EVT_BOX_HOLD);
			prd.setSht_ope_msg(inTrx.getHld_note());

			retPrdInfoDao.update(prd);

			// Add hold record
			Ret_prd_abn ret_prd_abn = new Ret_prd_abn();
			Ret_prd_abnId ret_prd_abnId = new Ret_prd_abnId();

			ret_prd_abnId.setPrd_seq_id_fk(prd.getPrd_seq_id());
			ret_prd_abnId.setEvt_seq_id_fk(gEvtSeqID);
			ret_prd_abn.setId(ret_prd_abnId);
			ret_prd_abn.setPrd_stat(prd.getPrd_stat());
			ret_prd_abn.setPv_prd_stat(prd.getPv_prd_stat_fk());

			ret_prd_abn.setEvt_cate(prd.getEvt_cate());
			ret_prd_abn.setEvt_usr(prd.getEvt_usr());
			ret_prd_abn.setEvt_timestamp(prd.getEvt_timestamp());
			ret_prd_abn.setRsn_cate_1(inTrx.getRsn_cate1());
			ret_prd_abn.setRsn_code_1(inTrx.getRsn_code1());

			retPrdAbnDao.save(ret_prd_abn);
		}

		ret_box.setBox_stat(PROC_HOLD);

		retBoxDao.update(ret_box);

		return lRc;
	}

}
